/*---------------------------------------------------------------------------*\
  =========                 |
  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
   \\    /   O peration     |
    \\  /    A nd           | www.openfoam.com
     \\/     M anipulation  |
-------------------------------------------------------------------------------
    Copyright (C) 2017-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
    This file is part of OpenFOAM.

    OpenFOAM is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    for more details.

    You should have received a copy of the GNU General Public License
    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.

InClass
    Foam::StringStream

Description
    Input/output from string buffers.

SourceFiles
    StringStream.C

\*---------------------------------------------------------------------------*/

#ifndef StringStream_H
#define StringStream_H

#include "ISstream.H"
#include "OSstream.H"
#include <sstream>

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

namespace Foam
{

namespace Detail
{

/*---------------------------------------------------------------------------*\
                Class Detail::StringStreamAllocator Declaration
\*---------------------------------------------------------------------------*/

//- Allocator for variants of a std stringstream
template<class StreamType>
class StringStreamAllocator
{
protected:

    // Protected Member Data

        //- The stream type
        typedef StreamType stream_type;

        //- The input/output stream.
        stream_type stream_;


    // Constructors

        //- Default construct
        StringStreamAllocator()
        :
            stream_()
        {}

        //- Copy construct from string
        StringStreamAllocator(const std::string& s)
        :
            stream_(s)
        {}


public:

    // Member Functions

        //- Get the string - as Foam::string rather than std::string
        Foam::string str() const
        {
            return Foam::string(stream_.str());
        }

        //- Set the string
        void str(const std::string& s)
        {
            stream_.str(s);
        }
};

} // End namespace Detail


/*---------------------------------------------------------------------------*\
                        Class IStringStream Declaration
\*---------------------------------------------------------------------------*/

//- Input from string buffer, using a ISstream
class IStringStream
:
    public Detail::StringStreamAllocator<std::istringstream>,
    public ISstream
{
    typedef Detail::StringStreamAllocator<std::istringstream> allocator_type;

public:

    // Constructors

        //- Default construct
        explicit IStringStream
        (
            streamFormat format=ASCII,
            versionNumber version=currentVersion
        )
        :
            allocator_type(),
            ISstream(stream_, "input", format, version)
        {}

        //- Construct from std::string
        explicit IStringStream
        (
            const std::string& s,
            streamFormat format=ASCII,
            versionNumber version=currentVersion,
            const Foam::string& name="input"
        )
        :
            allocator_type(s),
            ISstream(stream_, name, format, version)
        {}

        //- Construct from char*
        explicit IStringStream
        (
            const char* s,
            streamFormat format=ASCII,
            versionNumber version=currentVersion,
            const Foam::string& name="input"
        )
        :
            allocator_type(s),
            ISstream(stream_, name, format, version)
        {}

        //- Copy construct, copies content and format
        IStringStream(const IStringStream& str)
        :
            allocator_type(str.str()),
            ISstream(stream_, str.name(), str.format(), str.version())
        {}


    // Member Functions

        //- Reset the input buffer and rewind the stream
        virtual void reset(const std::string& s)
        {
            this->str(s);
            this->rewind();
        }

        //- Print stream description to Ostream
        virtual void print(Ostream& os) const;


    // Member Operators

        //- Return a non-const reference to const Istream
        //  Needed for read-constructors where the stream argument is temporary.
        Istream& operator()() const
        {
            return const_cast<IStringStream&>(*this);
        }
};


/*---------------------------------------------------------------------------*\
                        Class OStringStream Declaration
\*---------------------------------------------------------------------------*/

//- Output to string buffer, using a OSstream
class OStringStream
:
    public Detail::StringStreamAllocator<std::ostringstream>,
    public OSstream
{
    typedef Detail::StringStreamAllocator<std::ostringstream> allocator_type;

public:

    // Constructors

        //- Default construct
        explicit OStringStream
        (
            streamFormat format=ASCII,
            versionNumber version=currentVersion
        )
        :
            allocator_type(),
            OSstream(stream_, "output", format, version)
        {}

        //- Copy construct, copies content and format
        OStringStream(const OStringStream& str)
        :
            allocator_type(str.str()),
            OSstream(stream_, str.name(), str.format(), str.version())
        {}


    // Member Functions

        //- Reset the output buffer and rewind the stream
        void reset()
        {
            this->str("");  // No other way to reset the end
            this->rewind();
        }

        //- Rewind the output stream
        virtual void rewind()
        {
            // pubseekpos() instead of seekp() for symmetry with other classes
            stream_.rdbuf()->pubseekpos(0, std::ios_base::out);
        }

        //- Print stream description to Ostream
        virtual void print(Ostream& os) const;
};


// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

} // End namespace Foam

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

#endif

// ************************************************************************* //
